package asf.loaders
{
	import asf.core.Application;
	import asf.log.LogLevel;
	
	import br.com.stimuli.loading.BulkLoader;
	import br.com.stimuli.loading.BulkProgressEvent;
	
	import com.adobe.utils.StringUtil;
	import com.netoleal.utils.XMLUtils;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.media.SoundLoaderContext;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;
	
	[Event( name="complete", type="br.com.stimuli.loading.BulkProgressEvent" ) ]
	[Event( name="progress", type="br.com.stimuli.loading.BulkProgressEvent" ) ]
	
	public class AppLoader extends EventDispatcher
	{
		private var loader:BulkLoader;
		private var externalLoader:URLLoader;
		private var node:XMLList;
		private var app:Application;
		
		private var context:LoaderContext;
		private var soundContext:SoundLoaderContext;
		private var _started:Boolean = false;
		
		private var paused:Boolean = false;
		private var started:Boolean = false;
		private var externalLoaded:Boolean = false;
		private var finished:Boolean = false;
		private var queueStarted:Boolean = false;
		private var populated:Dictionary;
		
		public function AppLoader( p_dependenciesNode:XMLList, p_app:Application, useOwnContext:Boolean = false )
		{
			super( );

			node = p_dependenciesNode.copy( );
			app = p_app;
			
			context = new LoaderContext( );
			soundContext = new SoundLoaderContext( );
			populated = new Dictionary( );
			
			if( !useOwnContext )
			{
				context.applicationDomain = ApplicationDomain.currentDomain;
			}
			
			loader = new BulkLoader( BulkLoader.getUniqueName( ) );
			
			loader.addEventListener( BulkProgressEvent.COMPLETE, this.onLoadStatus );
			loader.addEventListener( BulkProgressEvent.PROGRESS, this.onLoadStatus );
			loader.addEventListener( Event.ACTIVATE, this.onLoadStatus );
			loader.addEventListener( Event.DEACTIVATE, this.onLoadStatus );
		}
		
		public function getBulkLoader( ):BulkLoader
		{
			return loader;
		}
		
		public function pause( ):void
		{
			paused = true;
			
			if( finished ) return;
			
			if( started )
			{
				if( externalLoader != null )
				{
					externalLoader.close( );
				}
				
				if( queueStarted )
				{
					loader.pauseAll( );
				}
			}
		}
		
		public function resume( ):void
		{
			paused = false;
			
			if( finished ) return;
			
			start( );
		}
		
		public function start( ):void
		{
			var f:String;
			
			f = external;
			started = true;
			
			if( paused ) return;
			
			if( f != "" )
			{
				loadExternalFile( f );
			}
			else
			{
				populateQueue( );
			}
		}
		
		private function loadExternalFile( f:String ):void
		{
			if( externalLoader != null )
			{
				try
				{
					externalLoader.close( );
				}
				catch( e:Error ){ }
				
				externalLoader.removeEventListener( Event.COMPLETE, externalOnLoad );
				externalLoader.removeEventListener( IOErrorEvent.IO_ERROR, externalOnError );
				
				externalLoader = null;
			}
			
			externalLoader = new URLLoader( );
			
			externalLoader.addEventListener( Event.COMPLETE, externalOnLoad );
			externalLoader.addEventListener( IOErrorEvent.IO_ERROR, externalOnError );
			
			externalLoader.load( new URLRequest( f ) );
		}
		
		private function externalOnLoad( evt:Event ):void
		{
			var externalData:XML = new XML( externalLoader.data );
			
			externalLoaded = true;
			
			populateWith( externalData.file );
			populateQueue( );
		}
		
		private function externalOnError( evt:IOErrorEvent ):void
		{
			populateQueue( );
		}
		
		private function populateQueue( ):void
		{
			queueStarted = true;
			
			populateWith( node.file );
			
			if( loader.itemsTotal > 0 )
			{
				loader.start( );
			}
			else
			{
				onLoadStatus( new BulkProgressEvent( BulkProgressEvent.COMPLETE ) );
			}
		}
		
		private function populateWith( files:XMLList ):void
		{
			var file:XML;
			var item:AppLoaderItem;
			
			var url:String;
			
			if( populated[ files ] == true ) return;
			
			populated[ files ] = true;
			
			for each( file in files )
			{
				if( testConditions( file ) )
				{
					item = new AppLoaderItem( file, app );
					item.context = item.type == BulkLoader.TYPE_SOUND? soundContext: context;
					
					url = item.url;
					
					app.log( "Adding: " + url + " [id]: " + item.id, LogLevel.INFO_3 );
					
					loader.add( url, item );
				}
			}
		}
		
		private function testConditions( fileNode:XML ):Boolean
		{
			var conditions:XMLList;
			var condition:XML;
			var attr:XML;
			var attrs:XMLList;
			var paramName:String;
			var paramValue:*;
			
			if( XMLUtils.nodeHasChilds( fileNode ) )
			{
				conditions = fileNode.conditions;
				for each( condition in conditions )
				{
					attrs = condition.attributes( );
					for each( attr in attrs )
					{
						paramName = String( attr.name( ) );
						paramValue = app.getParsedValueOf( String( attr ) );
						
						if( app.parameters[ paramName ] != paramValue ) return false;
					}
				}
			}
			
			return true;
		}
		
		private function onLoadStatus( evt:Event ):void
		{
			if( evt.type == BulkProgressEvent.COMPLETE )
			{
				finished = true;
			}
			
			this.dispatchEvent( evt );
		}
		
		private function get external( ):String
		{
			return StringUtil.trim( app.getParsedValueOf( node.@externalXML ) );
		}
		
		public function dispose( ):void
		{
			loader.removeEventListener( BulkProgressEvent.COMPLETE, this.onLoadStatus );
			loader.removeEventListener( BulkProgressEvent.PROGRESS, this.onLoadStatus );
			loader.removeEventListener( Event.ACTIVATE, this.onLoadStatus );
			loader.removeEventListener( Event.DEACTIVATE, this.onLoadStatus );
			
			loader.clear( );
			
			loader = null;
		}
	}
}